import { isEqual } from 'lodash-es'
import { UnwrapRef, WatchSource } from 'vue'

/**
 * 使用 `useState` 函数在 TypeScript 中创建一个可变的状态和更新该状态的函数。
 * @param initialValue 状态的初始值。
 * @returns 返回一个包含两个元素的数组：1. 可响应的状态；2. 用于更新状态的函数。
 */
export function useState<T>(initialValue: T): [Ref<UnwrapRef<T>>, (value: UnwrapRef<T>) => void] {
  // 创建一个初始状态的 ref
  const state = ref(initialValue)

  /**
   * 更新状态的函数。它将在下一个tick中异步更新状态值。
   * @param value 要设置的新状态值。
   */
  const setState = (value: UnwrapRef<T>) => {
    try {
      // 在更新之前，检查新旧值是否相等，如果相等则不进行更新
      if (isEqual(unref(state), value)) {
        return
      }
      // 异步更新状态，确保所有当前的异步操作完成后进行
      nextTick(() => {
        try {
          // 直接更新 ref 的值
          state.value = value
        } catch (error) {
          console.error('数据更新错误：', error)
          // 错误处理逻辑...
        }
      })
    } catch (error) {
      console.error('数据对比错误：', error)
      // 错误处理逻辑...
    }
  }

  return [state, setState]
}

/**
 * 使用Effect Hook，在组件的生命周期内执行指定的副作用操作。
 * @param effect 一个函数，包含了需要执行的副作用逻辑。
 * @param dependencies 可选参数，指定依赖数组，如果数组内元素发生变化，则重新执行effect函数。
 */
export function useEffect(effect: () => void, dependencies?: WatchSource<any>[]) {
  const isMounted = ref(false) // 用于记录组件是否已经挂载

  // 组件挂载时的处理逻辑
  const handleMount = () => {
    isMounted.value = true
    // 立即执行一次 effect
    try {
      effect()
    } catch (error) {
      console.error('组件挂载时执行 effect 错误：', error)
      // 错误处理逻辑...
    }
  }

  const handleUnmount = () => {
    isMounted.value = false
  } // 组件卸载时的处理逻辑

  onMounted(handleMount) // 组件挂载时调用的钩子
  onUnmounted(handleUnmount) // 组件卸载时调用的钩子

  // 如果存在依赖项，则使用 Vue 的 watch 来处理依赖变化
  if (dependencies && dependencies.length > 0) {
    watch(
      () => dependencies,
      () => {
        if (isMounted.value) {
          try {
            effect()
          } catch (error) {
            console.error('依赖变化时执行 effect 错误：', error)
            // 错误处理逻辑...
          }
        }
      },
      {
        deep: true, // 深度监听依赖变化
        immediate: true, // 立即执行一次回调，以保证初始状态的更新
      }
    )
  }
}
